package com.bayihouse.excel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.bayihouse.model.entity.*;
import com.bayihouse.model.excel.ExcelOccupant;
import com.bayihouse.utils.*;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

// 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
@NoArgsConstructor
@Data
public class ExcelOccupantListener implements ReadListener<ExcelOccupant> {

    /**
     * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 1000;

    public ExcelOccupantListener(ExcelCommunityUtils excelCommunityUtils) {
        this.excelCommunityUtils = excelCommunityUtils;
        this.administerList = excelCommunityUtils.getAdministerService().list();
    }


    private Set<Netobject> netobjectSet;

    /**
     * 缓存的数据
     */
    private List<Occupant> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    private ExcelCommunityUtils excelCommunityUtils;


    private List<Administer> administerList;


    @Override
    public void invoke(ExcelOccupant data, AnalysisContext context) {
        Occupant occupant = new Occupant();
        BeanUtils.copyProperties(data, occupant);
        String communityName = data.getCommunity();
        Netobject netobject = excelCommunityUtils.getNetobject(netobjectSet, communityName);
        String personType = data.getPersonType();
        String label = data.getLabel();
        Gson gson = new Gson();
        List<String> labelList = null;
        if (StringUtils.isNotBlank(label)) {
            labelList = gson.fromJson(label, new TypeToken<List<String>>() {
            }.getType());
        } else {
            labelList = new ArrayList<>();
        }
        labelList.add(personType);
        occupant.setLabel(gson.toJson(labelList));
        String addUserName = data.getAddUserName();
        String mannagerName = data.getMannagerName();
        String mannagerTelephone = data.getMannagerTelephone();
        String roomType = data.getRoomType();
        labelList.add(roomType);
        String addUserTelephone = data.getAddUserTelephone();
        Administer targetAddAdminister = null;
        if (StringUtils.isNotBlank(addUserName)) {
            for (Administer administer : administerList) {
                if (MyStringUtils.compareTwo(administer.getUserName(), addUserName) == 0) {
                    targetAddAdminister = administer;
                    break;
                }
            }
            if (targetAddAdminister == null) {
                targetAddAdminister = new Administer();
                targetAddAdminister.setTelephone(addUserTelephone);
                targetAddAdminister.setUserName(addUserName);
                excelCommunityUtils.getAdministerService().save(targetAddAdminister);
                administerList.add(targetAddAdminister);
            }
        }
        Administer targetManagerAdminister = null;
        if (StringUtils.isNotBlank(mannagerName)) {
            for (Administer administer : administerList) {
                if (MyStringUtils.compareTwo(administer.getUserName(), mannagerName) == 0) {
                    targetManagerAdminister = administer;
                    break;
                }
            }
            if (targetManagerAdminister == null) {
                targetManagerAdminister = new Administer();
                targetManagerAdminister.setTelephone(mannagerTelephone);
                targetManagerAdminister.setUserName(mannagerName);
                excelCommunityUtils.getAdministerService().save(targetManagerAdminister);
                administerList.add(targetManagerAdminister);
            }
        }
        String newLivingPlace = data.getNewLivingPlace();
        String newWorkplace = data.getNewWorkplace();
        if (StringUtils.isNotBlank(newWorkplace)) {
            occupant.setWorkplace(newWorkplace);
        }
        if (StringUtils.isNotBlank(newLivingPlace)) {
            occupant.setNowAddress(newLivingPlace);
        }
        try {
            occupant.setBirthday(MyDateUtils.getBirthday(occupant.getIdentity()));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        if (targetAddAdminister != null) {
            occupant.setAddUserId(targetAddAdminister.getId());
        }
        if (targetManagerAdminister != null) {
            occupant.setAdministerId(targetManagerAdminister.getId());
        }
        try {
            excelCommunityUtils.addExcelOccupation(cachedDataList, occupant, netobject.getTlist(), netobject);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成！");
    }


    /**
     * 加上存储数据库
     */
    private void saveData() {
        List<Community> communityList = MyObjectUtils.dealFlatStreamToList(netobjectSet.stream().map(Netobject::getTlist));
        SqlUtils.insertDataBase(communityList, excelCommunityUtils.getCommunityService());
        communityList.stream().forEach(object -> {
            object.setTId();
            object.setVId();
        });
        List<House> houseList = MyObjectUtils.dealFlatStreamToList(communityList.stream().filter(community -> {
            return community.getTlist() != null;
        }).map(Community::getTlist));
        SqlUtils.insertDataBase(houseList, excelCommunityUtils.getHouseService());
        houseList.stream().forEach(object -> {
            object.setTId();
        });
        List<Unit> unitList = MyObjectUtils.dealFlatStreamToList(houseList.stream().map(House::getTlist));
        SqlUtils.insertDataBase(unitList, excelCommunityUtils.getUnitService());
        unitList.stream().forEach(object -> {
            object.setTId();
        });
        Stream<List<Room>> businessRoomStream = communityList.stream().filter(community -> {
            boolean arraysEmpty = MyObjectUtils.isArraysEmpty(community.getVlist());
            return !arraysEmpty;
        }).map(Community::getVlist);
        Stream<List<Room>> listStream = unitList.stream().map(Unit::getTlist);
        Stream<List<Room>> sumStream = MyObjectUtils.mergeTwoStream(listStream, businessRoomStream);
        List<Room> roomList = MyObjectUtils.dealFlatStreamToList(sumStream);
        SqlUtils.insertDataBase(roomList, excelCommunityUtils.getRoomService());
        roomList.stream().forEach(object -> {
            object.setCId();
        });
        boolean b = excelCommunityUtils.getOccupantService().saveBatch(cachedDataList);
        if (b) {
            log.info("存储数据库成功！");
            return;
        }
        throw new RuntimeException("存储数据库失败！");
    }
}
